package com.net.web.server.strategy.impl;

import com.net.common.constant.Constant;
import com.net.common.entity.Message;
import com.net.common.exception.NetRuntimeException;
import com.net.common.util.MapUtils;
import com.net.common.util.MessageSerializableUtils;
import com.net.common.util.ThreadPoolFactory;
import com.net.common.util.HttpUtils;
import com.net.web.server.config.ServerConfig;
import com.net.web.server.server.ListenerProxySocketRunnable;
import com.net.web.server.strategy.IMessageStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.Objects;

import static com.net.web.server.config.ServerMapContext.clientIpMap;
import static com.net.web.server.config.ServerMapContext.clientSocketMap;
import static com.net.common.constant.Constant.MessageType.INTERNAL;
import static com.net.common.constant.Constant.TIME_OUT;

/**
 * 内部消息处理
 *
 * @author hjh
 */
@Service(INTERNAL)
@Slf4j
public class MessageInternalImpl implements IMessageStrategy<Message> {
    @Autowired
    private ServerConfig serverConfig;

    @Override
    public void execute(Message message, Socket clientSocket, Long sessionId) throws IOException {
        if (clientSocketMap.size() == ThreadPoolFactory.getMaxActive()) {
            throw new NetRuntimeException("超过最大连接数: " + ThreadPoolFactory.getMaxActive());
        }

        if (serverConfig.isEnableIp() && validateIp(clientSocket)) {
            throw new NetRuntimeException("同一个ip最多允许" + serverConfig.getIpNum() + "个连接!");
        }

        Integer port = HttpUtils.getPort();
        if (Objects.isNull(port)) {
            throw new NetRuntimeException("未获取到系统端口!");
        }

        clientSocketMap.put(sessionId, clientSocket);

        MessageSerializableUtils.sendSerializableMessage(clientSocket.getOutputStream(), () -> new Message(Constant.MessageType.INTERNAL, new byte[0], () -> MapUtils.createHashMap(Arrays.asList(MapUtils.createHashMap(TIME_OUT, String.valueOf(serverConfig.getTimeOut())), MapUtils.createHashMap("port", String.valueOf(port)))), sessionId));
        // 监听代理端口
        ThreadPoolFactory.execute(new ListenerProxySocketRunnable(clientSocket, sessionId, port));
    }

    @Override
    public void afterPropertiesSet() {
        MessageContext.register(INTERNAL, this);
    }

    private boolean validateIp(Socket clientSocket) {
        String ip = clientSocket.getInetAddress().getHostAddress();
        if (!clientIpMap.containsKey(ip)) {
            clientIpMap.put(ip, 1);
            return false;
        }
        clientIpMap.put(ip, clientIpMap.get(ip) + 1);
        return clientIpMap.get(ip) > serverConfig.getIpNum();
    }
}
